import config from '../config';
import {
    session,
    ksort,
    empty
} from './helper';
import {
    Base64
} from 'js-base64';
import {
    MD5,
    HmacSHA256
} from 'crypto-js';
import qs from 'qs';

const cookie = new session();

/**
 * 输出签名后参数
 *
 * @param    {object}  params     需要格式化的数据
 * @returns  void
 */
export function output(parameter) {
    // 数据格式化
    return formatData(parameter);
}

/**
 * 数据格式化
 *
 * @param    {object}  params     需要格式化的数据
 * @returns  void
 */
export function formatData(params) {
    let data = '',
        optios = {};
    if (params !== undefined) {
        optios = params;
    }
    return formatJson(optios)
}

// state防止CSRF
function createState(params) {
    const param = ksort(params);
    const string = qs.stringify(filterAndSort(param));
    const key = Base64.encode(MD5(string).toString());
    const value = new Date().getTime();
    let tmep = [];
    tmep[key] = value;
    let CSRF = cookie.get('CSRF');
    if (empty(CSRF)) {
        CSRF = Object.assign({}, tmep)
    } else {
        CSRF = Object.assign(CSRF, tmep)
    }
    cookie.set('CSRF', CSRF);
    return key;
}

// 验证state
export function checkState(params) {
    if (config.service.state == false) {
        return true;
    }
    let ret = false,
        value;
    const key = params.state;
    let CSRF = cookie.get('CSRF');
    if (empty(CSRF)) {
        return false;
    } else {
        Object.keys(CSRF).forEach(function(k) {
            if (key === k) {
                ret = true;
                value = CSRF[k];
                delete CSRF[k];
            }
        });
    }
    // API网络请求是否超时
    if (ret && config.service.times_out > 0) {
        if (!empty(value) && ((new Date().getTime() - value) / 1000) <= config.service.times_out) {
            ret = true;
            cookie.set('CSRF', CSRF);
        } else {
            ret = false;
        }
    }
    return ret;
}

// 生成SIGN
function createSign(params) {
    //签名步骤一：生成待签名字符串
    let str = createSignString(params);
    //签名步骤二：在string后加入KEY
    str = str + "&key=" + String(config.service.key);
    //签名步骤三：MD5加密或者HMAC-SHA256
    if (String(config.service.sign_type).toUpperCase() == "MD5") {
        str = MD5(str).toString();
    } else if (String(config.service.sign_type).toUpperCase() == "HMAC-SHA256" || String(config.service.sign_type).toUpperCase() == "SHA256") {
        str = HmacSHA256(str, String(config.service.key)).toString();
    }
    //签名步骤四：所有字符转为大写
    str = String(str).toUpperCase();
    //签名步骤五：Base64编码
    return Base64.encode(str);
}

// 验证签名(服务器返回数据)
export function checkSign(data) {
    const sign_old = data.sign,
        sign_new = createSign(data)
    if (sign_old == sign_new) {
        return true;
    } else {
        return false;
    }
}

// 生成待签名字符串
function createSignString(data) {
    delete data.sign;
    const appConfig = {
            app_id: String(config.service.app_id),
            app_secret: String(config.service.app_secret)
        },
        str_1 = objectToString(filterAndSort(data)),
        str_2 = objectToString(filterAndSort(appConfig)),
        str = str_1 + '&' + str_2;
    return str;
}

/**
 * 多维对象转字符串
 * @param array $params
 * @return string
 * @author  By Taoge 2018/8/9 13:32
 */
function objectToString($params) {
    if (typeof($params) === 'object') {
        let $buff = '';
        Object.keys($params).forEach(function($k) {
            if (typeof($params[$k]) === 'object') {
                if ($buff === '') {
                    $buff += $k + '=' + objectToString($params[$k]);
                } else {
                    $buff += '&' + $k + '=' + objectToString($params[$k]);
                }
            } else {
                if ($buff === '') {
                    $buff += $k + '=' + $params[$k];
                } else {
                    $buff += '&' + $k + '=' + $params[$k];
                }
            }
        });
        return $buff;
    } else {
        return $params;
    }
}

function formatXml(params) {
    let xmlString = {
        data: params,
        sign: '',
        state: '',
        timestamps: ''
    };
    if (config.service.times_out > 0) {
        xmlString.timestamps = Date.parse(new Date()) / 1000;
    }
    if (config.service.state) {
        xmlString.state = createState(params);
    }
    if (config.service.is_sign) {
        xmlString.sign = createSign(xmlString);
    }
    return jsonToXml(xmlString);
}

function formatJson(params) {
    let jsonString = {
        data: params,
        sign: '',
        state: '',
        timestamps: ''
    };
    if (config.service.times_out > 0) {
        jsonString.timestamps = Date.parse(new Date()) / 1000;
    }
    if (config.service.state) {
        jsonString.state = createState(params);
    }
    if (config.service.is_sign) {
        jsonString.sign = createSign(jsonString);
    }
    return JSON.stringify(jsonString);
}

// 筛选并排序
function filterAndSort(params) {
    if (typeof(params) === 'object' && JSON.stringify(params) !== "{}" && params !== null) {
        let $params = ksort(params),
            $filterAndSort = {};
        Object.keys($params).forEach(function($k) {
            if (typeof($params[$k]) === 'object' && JSON.stringify($params[$k]) !== "{}" && $params[$k] !== null) {
                $filterAndSort[$k] = filterAndSort($params[$k]);
            } else {
                if (false === empty($params[$k]) /*&& "@" !== String($params[$k]).substr(0, 1)*/ ) {
                    //$filterAndSort[$k] = escapeCorrection($params[$k]);
                    $filterAndSort[$k] = $params[$k];
                }
            }
        });
        return ksort($filterAndSort);
    } else {
        return params;
    }
}

//转义校正
function escapeCorrection(params) {
    if (String(params).indexOf('&') !== -1) {
        params = HTMLEncode(params);
    }
    return params;
}

//HTML转义
function HTMLEncode(html) {
    let temp = document.createElement("div");
    (temp.textContent != null) ? (temp.textContent = html) : (temp.innerText = html);
    let output = temp.innerHTML;
    temp = null;
    return output;
}

//HTML反转义
function HTMLDecode(text) {
    let temp = document.createElement("div");
    temp.innerHTML = text;
    let output = temp.innerText || temp.textContent;
    temp = null;
    return output;
}